import { Curve2 } from "../curve/Curve2";
import { IntersectionType } from "../curve/IntersectionType";
import { Polygon2 } from "./Polygon2";
import { IntersectPoint } from "./IntersectPoint";
import { TrimCurve } from "./TrimCurve";
import { Curve2Type } from "../curve/Curve2Type";
import { Arc2 } from "../curve/Arc2";
import { Segment2 } from "../curve/Segment2";
import { Point2 } from "../point/Point2";

/**
* @description 2D 草图类，实现添加曲线，获取封闭区域的功能
* @author xuld
* @date 2024-11-14
* @lastEditTime 2024-11-14 17:29:38
* @lastEditors xuld
*/

export class Sketch {
    // 曲线数组
    private curves: Array<Curve2> = [];
    // 交点信息映射表 key 为曲线，value 为交点信息数组
    private intersectPointMap = new Map<Curve2, Array<IntersectPoint>>();

    /**
     * @description添加曲线
     * @param curve 要添加的曲线
     */
    addCurve(curve: Curve2): void {
        if (!this.curves.includes(curve)) {
            this.curves.push(curve);
            this.updateIntersectPoints(curve);
        }
    }

    /**
     * @description 更新曲线的交点信息
     * @param curve - 曲线
     */
    private updateIntersectPoints(curve: Curve2): void {
        const pointInfos: Array<IntersectPoint> = [];

        // 计算与其他曲线的交点
        for (const other of this.curves) {
            if (other == curve) {
                continue;
            }

            const intersects = curve.intersect(other);
            if (intersects.type === IntersectionType.disjoint) {
                continue;
            }

            for (const point of intersects.intersectPoints) {
                const param1 = curve.getParameter(point);
                const param2 = other.getParameter(point);
                pointInfos.push({
                    point: point,
                    param: param1,
                    curve: curve,
                    otherCurve: other,
                    otherParam: param2
                });
            }
        }

        // 按参数排序
        pointInfos.sort((a, b) => a.param - b.param);
        this.intersectPointMap.set(curve, pointInfos);
    }

    /**
     * @description 从草图中删除曲线
     * @param curve 要删除的曲线
     * 
     * 删除流程:
     * 1. 从曲线数组中移除目标曲线
     * 2. 删除与该曲线相关的所有交点信息
     * 3. 更新其他曲线的交点信息
     */
    deleteCurve(curve: Curve2): void {
        // 从曲线数组中移除
        const index = this.curves.indexOf(curve);
        if (index === -1) {
            return;
        }
        // 删除该曲线的交点信息
        this.curves.splice(index, 1);
        this.intersectPointMap.delete(curve);

        // 从其他曲线的交点信息中删除与该曲线相关的交点
        for (const [otherCurve, points] of this.intersectPointMap) {
            const newPoints = points.filter(point => point.otherCurve !== curve);
            this.intersectPointMap.set(otherCurve, newPoints);
        }
    }

    /**
     * @description 根据ID取曲线
     * @param id 曲线ID
     * @returns 曲线
     */
    getCurveById(id: number): Curve2 | undefined {
        return this.curves.find(c => c.id === id);
    }

    /**
     * @description 从草图中删除指定ID的曲线
     * @param id 曲线ID
     * @returns 是否删除成功
     */
    deleteCurveById(id: number): boolean {
        const curve = this.getCurveById(id);
        if (curve) {
            this.deleteCurve(curve);
            return true;
        }
        return false;
    }

    /**
     * @description 清空草图中的所有曲线
     */
    clear(): void {
        this.curves = [];
        this.intersectPointMap.clear();
    }

    /**
     * @description 获取封闭区域
     * @returns 封闭区域数组
     */
    getAllClosedAreas(): Polygon2[] {
        const result: Polygon2[] = [];

        // 如果没有曲线,直接返回
        if (this.curves.length === 0) {
            return result;
        }

        // 1. 分组处理曲线
        const groups = this.splitGroups();

        // 2. 处理每个组
        for (const group of groups) {
            const areas = this.searchOutestArea(group);
            if (areas.length === 0) continue;

            // 3. 处理每个区域
            for (const area of areas) {
                const profiles = this.splitChildFormNest(area);

                // 4. 处理多边形的父子关系
                this.buildPolygonHierarchy(profiles);

                // 5. 只添加根多边形（没有父多边形的多边形）
                for (const polygon of profiles) {
                    if (!polygon.getParent()) {
                        result.push(polygon);
                    }
                }
            }
        }

        return result;
    }

    /**
     * @description 构建多边形的父子关系
     * @param polygons - 多边形数组
     * 
     * 构建规则:
     * 1. 按面积从大到小排序
     * 2. 对每个多边形，检查是否被其他多边形包含
     * 3. 如果被包含，则成为包含它的最小多边形的子多边形
     * 4. 如果不被任何多边形包含，则为根多边形
     */
    private buildPolygonHierarchy(polygons: Polygon2[]): void {
        // 按面积从大到小排序
        polygons.sort((a, b) => {
            const areaA = this.calculateArea(a.getBoundary());
            const areaB = this.calculateArea(b.getBoundary());
            return areaB - areaA;
        });

        // 构建父子关系
        for (let i = 0; i < polygons.length; i++) {
            const current = polygons[i];

            // 如果已经有父多边形，跳过
            if (current.getParent()) continue;

            for (let j = 0; j < i; j++) {
                const potential = polygons[j];
                const relation = this.getPolygonRelation(potential, current);

                if (relation > 0) { // potential 包含 current
                    // 检查是否是最小的包含多边形
                    let isSmallestContainer = true;
                    for (let k = j + 1; k < i; k++) {
                        const intermediate = polygons[k];
                        if (this.getPolygonRelation(intermediate, current) > 0 &&
                            this.getPolygonRelation(potential, intermediate) > 0) {
                            isSmallestContainer = false;
                            break;
                        }
                    }

                    if (isSmallestContainer) {
                        potential.addHole(current);
                        break;
                    }
                }
            }
        }

        // 验证和修复父子关系
        this.validatePolygonHierarchy(polygons);
    }

    /**
     * @description 验证和修复多边形的父子关系
     * @param polygons - 多边形数组
     * 
     * 验证规则:
     * 1. 每个多边形最多只能有一个父多边形
     * 2. 不能形成循环引用
     * 3. 子多边形必须完全在父多边形内部
     * 4. 同级的多边形不能相交
     */
    private validatePolygonHierarchy(polygons: Polygon2[]): void {
        for (const polygon of polygons) {
            const parent = polygon.getParent();
            if (!parent) continue;

            // 检查是否完全在父多边形内
            const point = polygon.getRandomPoint();
            if (!parent.containsPoint(point)) {
                // 关系错误，移除父子关系
                parent.removeHole(polygon);
                continue;
            }

            // 检查同级多边形是否相交
            const siblings = parent.getHoles();
            for (const sibling of siblings) {
                if (sibling === polygon) continue;

                // 如果同级多边形相交，保留面积较大的
                if (this.polygonsIntersect(polygon, sibling)) {
                    const areaPolygon = this.calculateArea(polygon.getBoundary());
                    const areaSibling = this.calculateArea(sibling.getBoundary());

                    if (areaPolygon > areaSibling) {
                        parent.removeHole(sibling);
                    } else {
                        parent.removeHole(polygon);
                        break;
                    }
                }
            }
        }
    }

    /**
     * @description 检查两个多边形是否相交
     */
    private polygonsIntersect(p1: Polygon2, p2: Polygon2): boolean {
        // 检查边界曲线是否相交
        const boundary1 = p1.getBoundary();
        const boundary2 = p2.getBoundary();

        for (const curve1 of boundary1) {
            for (const curve2 of boundary2) {
                const intersects = curve1.intersect(curve2);
                if (intersects.type !== IntersectionType.disjoint) {
                    return true;
                }
            }
        }

        // 检查一个多边形是否包含另一个多边形的点
        const p1Point = p1.getRandomPoint();
        const p2Point = p2.getRandomPoint();

        return p1.containsPoint(p2Point) || p2.containsPoint(p1Point);
    }

    /**
     * @description 将曲线分组,相交的曲线在同一组
     * @returns 分组后的曲线数组
     * 
     * 分组规则:
     * 1. 从任意一条未分组的曲线开始
     * 2. 找出与该曲线相交的所有曲线,加入同一组
     * 3. 对新加入的曲线重复步骤2,直到没有新的相交曲线
     * 4. 重复1-3步骤,直到所有曲线都被分组
     * 
     * 相交判定:
     * 1. 两条曲线有交点
     * 2. 两条曲线端点重合
     * 3. 两条曲线重合或部分重合
     * 
     * 分组结果:
     * 1. 每个组内的曲线都是相互连通的
     * 2. 不同组之间的曲线没有任何连接关系
     * 3. 单独的曲线会形成只有一条曲线的组
     * 
     * 用途:
     * 1. 提高后续封闭区域搜索的效率
     * 2. 避免处理不相关曲线的交点
     * 3. 便于并行处理不同的封闭区域
     */
    private splitGroups(): Array<Array<Curve2>> {
        const groups: Array<Array<Curve2>> = [];
        const usedCurves = new Set<Curve2>();

        for (const curve of this.curves) {
            if (usedCurves.has(curve)) {
                continue;
            }
            usedCurves.add(curve);

            const group: Array<Curve2> = [curve];
            let hasNew = true;
            while (hasNew) {
                hasNew = false;
                for (const c1 of group) {
                    for (const c2 of this.curves) {
                        if (usedCurves.has(c2)) continue;

                        const intersects = c1.intersect(c2);
                        if (intersects.type !== IntersectionType.disjoint) {
                            group.push(c2);
                            usedCurves.add(c2);
                            hasNew = true;
                        }
                    }
                }
            }
            groups.push(group);
        }

        return groups;
    }

    /**
     * @description 搜索最外层封闭区域
     * @param curves - 输入的曲线数组
     * @returns 找到的最外层区域的TrimCurve数组
     * 
     * 搜索流程:
     * 1. 找到最左侧的交点作为起始点
     *    - 遍历所有曲线的交点
     *    - 选择x坐标最小的点作为起始点
     * 
     * 2. 从起始点开始搜索封闭区域
     *    - 创建当前片段的TrimCurve
     *    - 记录当前曲线ID和参数
     *    - 设置前进方向(isForward)
     * 
     * 3. 寻找下一个交点
     *    - 获取当前曲线上的所有交点
     *    - 使用最小角度原则选择下一个点
     *    - 考虑曲率因素进行选择
     * 
     * 4. 处理特殊情况
     *    - 到达端点：记录终点参数并结束当前片段
     *    - 回到起点：形成封闭区域，加入结果集
     *    - 无下一点：结束搜索
     * 
     * 5. 更新搜索位置
     *    - 记录下一条曲线ID和参数
     *    - 更新当前位置继续搜索
     * 
     * 最小角度原则:
     * 1. 计算当前切向量与候选点切向量的夹角
     * 2. 选择夹角最小的点作为下一个
     * 3. 当夹角相近时考虑曲率因素
     * 
     * 曲率考虑:
     * 1. 当夹角接近180度时
     *    - 两条直线：保持原方向
     *    - 直线和曲线：优先选择曲线方向
     *    - 两条曲线：选择曲率较大的方向
     * 
     * 2. 当夹角接近0度时
     *    - 优先选择曲率变化较小的方向
     * 
     * 返回结果:
     * 1. 每个TrimCurve数组代表一个封闭区域
     * 2. 每个TrimCurve包含:
     *    - curveId: 曲线ID
     *    - startParam: 起始参数
     *    - endParam: 终止参数
     *    - isForward: 前进方向
     *    - direction: 切向量
     *    - nextCurveId: 下一条曲线ID
     *    - nextParam: 下一条曲线的参数
     */
    private searchOutestArea(curves: Array<Curve2>): Array<Array<TrimCurve>> {
        const result: Array<Array<TrimCurve>> = [];

        // 1. 找到最左侧的点
        let minX = Number.MAX_VALUE;
        let startCurve: Curve2 | undefined;
        let startParam = 0;

        for (const curve of curves) {
            const points = this.intersectPointMap.get(curve) || [];
            for (const pt of points) {
                if (pt.point.x < minX) {
                    minX = pt.point.x;
                    startCurve = curve;
                    startParam = pt.param;
                }
            }
        }

        if (!startCurve) return result;

        // 2. 从起始点开始搜索封闭区域
        const trimCurves: Array<TrimCurve> = [];
        let currentCurve = startCurve;
        let currentParam = startParam;

        while (true) {
            // 创建当前片段
            const trim = new TrimCurve();
            trim.curveId = currentCurve.id;
            trim.startParam = currentParam;
            trim.isForward = true;

            // 获取下一个交点
            const points = this.intersectPointMap.get(currentCurve) || [];
            let nextPoint = this.findNextPoint(currentCurve, currentParam, points);

            if (!nextPoint) {
                // 处理到达端的情况
                trim.endParam = currentCurve.getParameter(currentCurve.end);
                trim.direction = currentCurve.tangentAt(trim.endParam);
                trimCurves.push(trim);
                break;
            }

            trim.endParam = nextPoint.param;
            trim.direction = currentCurve.tangentAt(trim.endParam);
            trim.nextCurveId = nextPoint.otherCurve.id;
            trim.nextParam = nextPoint.otherParam;
            trimCurves.push(trim);

            // 检查是否回到起点
            if (nextPoint.point.equals(startCurve.start) && trimCurves.length > 2) {
                result.push([...trimCurves]);
                break;
            }

            // 更新当前位置
            currentCurve = nextPoint.otherCurve;
            currentParam = nextPoint.otherParam;
        }

        return result;
    }

    /**
     * @description 处理子区域，将一组TrimCurve分割成多个不相交的封闭区域
     * @param trimCurves - 输入的TrimCurve数组
     * @returns 处理后的多边形数组
     * 
     * 处理流程:
     * 1. 删除重合线段
     *    - 检查所有线段是否有重合部分
     *    - 合并重合的线段参数范围
     *    - 删除完全重合的线段
     * 
     * 2. 处理桥接情况
     *    - 桥接定义：两个封闭区域通过一条或多条线段连接
     *    - 桥接特征：
     *      a. 同一条曲线在不同位置被使用
     *      b. 曲线的起点和终点重合
     *      c. 形成了多个封闭环
     *    - 处理方法：
     *      a. 检测桥接点
     *      b. 在桥接点处分割
     *      c. 分别形成独立的封闭区域
     * 
     * 3. 创建多边形
     *    - 为每个封闭区域创建Polygon2对象
     *    - 根据TrimCurve创建新的曲线
     *    - 设置多边形的边界
     * 
     * 特殊情况处理:
     * 1. 重合线段
     *    - 完全重合：保留一条
     *    - 部分重合：分割后重新组合
     *    - 方向相反：考虑方向因素
     * 
     * 2. 周期性曲线
     *    - 圆弧跨越0度线
     *    - 参数范围标准化
     *    - 考虑周期性重合
     * 
     * 3. 数值精度
     *    - 端点重合判断
     *    - 参数相等判断
     *    - 角度计算精度
     * 
     * 返回结果:
     * 1. 每个Polygon2代表一个独立的封闭区域
     * 2. 区域之间没有重叠或连接
     * 3. 保持原始曲线的几何特征
     * 
     * 应用场景:
     * 1. 处理复杂的封闭区域
     * 2. 分离相交的区域
     * 3. 清理无效的连接
     * 
     * 注意事项:
     * 1. 输入的TrimCurve必须是有序的
     * 2. 曲线必须首尾相连
     * 3. 参数范围必须有效
     * 4. 需要考虑数值精度问题
     */
    private splitChildFormNest(trimCurves: Array<TrimCurve>): Array<Polygon2> {
        const result: Array<Polygon2> = [];

        // 1. 删除重合线段
        const simplified = this.deleteOverlaps(trimCurves);

        // 2. 处理桥接情况
        const bridgeRemoved = this.deleteBridge(simplified);

        // 3. 创建多边形
        for (const curves of bridgeRemoved) {
            const polygon = new Polygon2();
            const boundary: Array<Curve2> = [];

            for (const trim of curves) {
                const curve = this.getCurveById(trim.curveId);
                if (curve) {
                    // 根据参数范围创建新的曲线
                    const newCurve = this.createTrimmedCurve(curve, trim);
                    if (newCurve) boundary.push(newCurve);
                }
            }

            if (boundary.length > 0) {
                polygon.setBoundary(boundary);
                result.push(polygon);
            }
        }

        return result;
    }

    /**
     * @description 删除重合线段
     */
    private deleteOverlaps(curves: Array<TrimCurve>): Array<TrimCurve> {
        const result: Array<TrimCurve> = [];
        const used = new Set<number>();

        for (let i = 0; i < curves.length; i++) {
            if (used.has(i)) continue;

            const curve1 = curves[i];
            let hasOverlap = false;

            for (let j = i + 1; j < curves.length; j++) {
                if (used.has(j)) continue;

                const curve2 = curves[j];
                if (curve1.curveId === curve2.curveId) {
                    // 检查是否重合
                    if (this.isOverlap(curve1, curve2)) {
                        used.add(j);
                        hasOverlap = true;
                        // 合并参数范围
                        curve1.startParam = Math.min(curve1.startParam, curve2.startParam);
                        curve1.endParam = Math.max(curve1.endParam, curve2.endParam);
                    }
                }
            }

            if (!hasOverlap) {
                result.push(curve1);
            }
        }

        return result;
    }

    /**
     * @description 检查两个片段是否重合
     */
    private isOverlap(curve1: TrimCurve, curve2: TrimCurve): boolean {
        const c1 = this.getCurveById(curve1.curveId);
        if (!c1) return false;

        // 检查参数范围是否有重叠
        let hasParamOverlap = false;

        if (c1.curveType === Curve2Type.Arc) {
            const arc = c1 as Arc2;
            if ((arc as Arc2).isClosed()) {
                // 周期性曲线需要特殊处理
                const period = Math.PI * 2;
                const start1 = curve1.startParam % period;
                const end1 = curve1.endParam % period;
                const start2 = curve2.startParam % period;
                const end2 = curve2.endParam % period;

                if (start1 <= end1) {
                    hasParamOverlap = !(end2 < start1 || start2 > end1);
                } else {
                    hasParamOverlap = !(end2 < start1 && start2 > end1);
                }
            } else {
                hasParamOverlap = !(
                    curve1.endParam < curve2.startParam ||
                    curve2.endParam < curve1.startParam
                );
            }
        } else {
            hasParamOverlap = !(
                curve1.endParam < curve2.startParam ||
                curve2.endParam < curve1.startParam
            );
        }

        if (!hasParamOverlap) return false;

        // 检查方向是否相同
        const dir1 = c1.tangentAt(curve1.startParam);
        const dir2 = c1.tangentAt(curve2.startParam);

        // 考虑正反向
        const angle = Math.abs(dir1.angleTo(dir2));
        return angle < 1e-6 || Math.abs(angle - Math.PI) < 1e-6;
    }

    /**
     * @description 删除桥接
     */
    private deleteBridge(curves: Array<TrimCurve>): Array<Array<TrimCurve>> {
        const result: Array<Array<TrimCurve>> = [];
        let current: Array<TrimCurve> = [];

        for (let i = 0; i < curves.length; i++) {
            const curve = curves[i];
            current.push(curve);

            // 检查是否形成桥接
            if (current.length >= 2) {
                const first = current[0];
                const last = current[current.length - 1];

                if (first.curveId === last.curveId &&
                    Math.abs(first.startParam - last.endParam) < 1e-6) {
                    // 找到一个封闭区域
                    result.push([...current]);
                    current = [];
                }
            }
        }

        if (current.length > 0) {
            result.push(current);
        }

        return result;
    }

    /**
     * @description 根据小角度原则找到下一个点
     */
    private findNextPoint(curve: Curve2, param: number, points: Array<IntersectPoint>): IntersectPoint | undefined {
        let result: IntersectPoint | undefined;
        let minAngle = Math.PI * 2;

        const currentTangent = curve.tangentAt(param);
        const currentCurvature = curve.curvatureAt(param);

        // 按参数排序
        points.sort((a, b) => a.param - b.param);

        for (const pt of points) {
            // 跳过当点
            if (Math.abs(pt.param - param) < 1e-6) continue;

            // 跳过已经处理过的点
            if (pt.param < param) continue;

            const nextTangent = pt.otherCurve.tangentAt(pt.otherParam);
            const nextCurvature = pt.otherCurve.curvatureAt(pt.otherParam);

            let angle = currentTangent.angleTo(nextTangent);

            // 处理180度的特殊情况
            if (Math.abs(angle - Math.PI) < 1e-6) {
                // 根据曲率调整角度
                if (Math.abs(currentCurvature) < 1e-6 && Math.abs(nextCurvature) < 1e-6) {
                    // 都是直线,保持原角度
                    // 检查是否有其他更优的选择
                    continue;
                } else if (Math.abs(currentCurvature) < 1e-6) {
                    angle = nextCurvature > 0 ? Math.PI : -Math.PI;
                } else if (Math.abs(nextCurvature) < 1e-6) {
                    angle = currentCurvature > 0 ? -Math.PI : Math.PI;
                } else {
                    // 根据曲率的大小关系调整角度
                    if (Math.abs(currentCurvature) > Math.abs(nextCurvature)) {
                        angle = currentCurvature > 0 ? -Math.PI : Math.PI;
                    } else {
                        angle = nextCurvature > 0 ? Math.PI : -Math.PI;
                    }
                }
            }

            // 处理接近0度的情况
            if (Math.abs(angle) < 1e-6) {
                // 优先选择曲率变较小的
                if (Math.abs(currentCurvature - nextCurvature) < 1e-6) {
                    result = pt;
                    break;
                }
                continue;
            }

            if (angle < minAngle) {
                minAngle = angle;
                result = pt;
            }
        }

        return result;
    }

    /**
     * @description 根据参数范围创建新的曲线
     */
    private createTrimmedCurve(curve: Curve2, trim: TrimCurve): Curve2 | undefined {
        // 根据曲线类型处理参数范围
        if (curve.curveType === Curve2Type.Arc) {
            const arc = curve as Arc2;
            // 创建新的圆弧
            return new Arc2(
                trim.startParam,
                trim.endParam,
                arc.center,
                arc.radius
            );
        } else if (curve.curveType === Curve2Type.Segment) {
            const startPoint = curve.d0(trim.startParam);
            const endPoint = curve.d0(trim.endParam);
            // 创建新的线段
            return new Segment2(
                trim.isForward ? startPoint : endPoint,
                trim.isForward ? endPoint : startPoint
            );
        }

        return curve.clone();
    }

    /**
    * @description 转换为字符串表示
    * @returns 格式化的点字符串
    */
    public toString(): string {
        let curvesStr = '';
        let intersectStr = '';
        return `{"type": "Sketch", "curves": ${curvesStr}, "IntersectPoints": ${intersectStr}}`;
    }

    /**
     * @description 计算多边形面积
     */
    private calculateArea(curves: Array<Curve2>): number {
        let area = 0;
        for (let i = 0; i < curves.length; i++) {
            const curve = curves[i];

            // 使用梯形法则计算面积
            if (curve.curveType === Curve2Type.Segment) {
                const p1 = curve.start;
                const p2 = curve.end;
                area += (p2.x - p1.x) * (p2.y + p1.y) / 2;
            } else if (curve.curveType === Curve2Type.Arc) {
                const arc = curve as Arc2;
                // 圆弧面积 = 扇形面积 - 三角形面积
                const angle = arc.endAngle - arc.startAngle;
                const r = arc.radius;
                const sectorArea = angle * r * r / 2;
                const triangleArea = r * r * Math.sin(angle) / 2;
                area += sectorArea - triangleArea;
            }
        }
        return Math.abs(area);
    }

    /**
     * @description 获取两个多边形的包含关系
     * @returns 1: p1包含p2, -1: p2包含p1, 0: 无包含关系
     */
    private getPolygonRelation(p1: Polygon2, p2: Polygon2): number {
        // 1. 检查边界是否相交
        const boundary1 = p1.getBoundary();
        const boundary2 = p2.getBoundary();

        for (const curve1 of boundary1) {
            for (const curve2 of boundary2) {
                const intersects = curve1.intersect(curve2);
                if (intersects.type !== IntersectionType.disjoint) {
                    return 0; // 边界相交，无包含关系
                }
            }
        }

        // 2. 检查一个点是否在另一个多边形内
        const point = p2.getRandomPoint();
        if (this.isPointInPolygon(point, boundary1)) {
            return 1; // p1 包含 p2
        }

        const point2 = p1.getRandomPoint();
        if (this.isPointInPolygon(point2, boundary2)) {
            return -1; // p2 包含 p1
        }

        return 0;
    }

    /**
     * @description 判断点是否在多边形内
     */
    private isPointInPolygon(point: Point2, curves: Array<Curve2>): boolean {
        let windingNumber = 0;

        for (const curve of curves) {
            if (curve.curveType === Curve2Type.Segment) {
                const segment = curve as Segment2;
                if (this.rayIntersectsSegment(point, segment)) {
                    windingNumber++;
                }
            } else if (curve.curveType === Curve2Type.Arc) {
                const arc = curve as Arc2;
                windingNumber += this.rayIntersectsArc(point, arc);
            }
        }

        return windingNumber % 2 !== 0;
    }

    /**
     * @description 射线与线段相交检测
     */
    private rayIntersectsSegment(point: Point2, segment: Segment2): boolean {
        if ((segment.start.y > point.y) !== (segment.end.y > point.y)) {
            const intersectX = segment.start.x +
                (point.y - segment.start.y) *
                (segment.end.x - segment.start.x) /
                (segment.end.y - segment.start.y);

            if (point.x < intersectX) {
                return true;
            }
        }
        return false;
    }

    /**
     * @description 射线与圆弧相交检测
     */
    private rayIntersectsArc(point: Point2, arc: Arc2): number {
        // 计算点到圆心的向量
        const toCenter = point.vectorTo(arc.center);
        const radius = arc.radius;

        // 如果点在圆外且y坐标在圆弧范围内
        const dist = Math.sqrt(toCenter.x * toCenter.x + toCenter.y * toCenter.y);
        if (dist > radius &&
            point.y > arc.center.y - radius &&
            point.y < arc.center.y + radius) {

            // 计算射线与圆的交点
            const discriminant = radius * radius -
                (point.y - arc.center.y) * (point.y - arc.center.y);

            if (discriminant >= 0) {
                const intersectX = arc.center.x + Math.sqrt(discriminant);
                if (point.x < intersectX) {
                    // 检查交点是否在圆弧范围内
                    const angle = Math.atan2(
                        point.y - arc.center.y,
                        intersectX - arc.center.x
                    );
                    if (angle >= arc.startAngle && angle <= arc.endAngle) {
                        return 1;
                    }
                }
            }
        }
        return 0;
    }
}